using System;
using System.Linq;
using System.Xml.Linq;
using Coderoom.ScrumPlanner.Data.Contracts;
using Coderoom.ScrumPlanner.Domain;
using Coderoom.ScrumPlanner.Utilities;

namespace Coderoom.ScrumPlanner.Data.Repositories.Xml
{
	public sealed class XmlSprintRepository : XmlRepository, ISprintRepository
	{
		public override string DataFileName
		{
			get { return "Sprints.xml"; }
		}

		#region ISprintRepository Members

		public SprintCollection GetSprints(Guid projectId)
		{
			Lock.EnterReadLock();

			try
			{
				var result = GetSprintsInternal().Where(sprint => sprint.ProjectId == projectId).ToArray();
				return new SprintCollection(result);
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public Sprint GetSprint(Guid sprintId)
		{
			Lock.EnterReadLock();

			try
			{
				return GetSprintsInternal().Where(sprint => sprint.Id == sprintId).SingleOrDefault();
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public void CreateSprint(Sprint sprint)
		{
			Lock.EnterWriteLock();

			try
			{
				sprint.Id = Guid.NewGuid();

				var sprintData = ReadXml();
				// ReSharper disable PossibleNullReferenceException
				sprintData.Root.Add(new XElement("Sprint", new XAttribute("id", sprint.Id), new XAttribute("projectId", sprint.ProjectId), new XElement("Title", sprint.Title), new XElement("Slug", sprint.Slug)));
				// ReSharper restore PossibleNullReferenceException
				WriteXml(sprintData);
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		public bool DeleteSprint(Guid sprintId)
		{
			Lock.EnterWriteLock();

			try
			{
				var sprintData = ReadXml();

				var sprintToDelete = sprintData.ImmediateDescendants("Sprint").Where(sprint => sprint.ReadAttributeAsGuid("id") == sprintId).SingleOrDefault();

				if (sprintToDelete != null)
				{
					sprintToDelete.Remove(); // removes it from parent
					WriteXml(sprintData);
					return true;
				}

				return false;
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		#endregion

		private IQueryable<Sprint> GetSprintsInternal()
		{
			var sprintData = ReadXml();

			return (from sprint in sprintData.ImmediateDescendants("Sprint")
			        select new Sprint {Id = sprint.ReadAttributeAsGuid("id"), ProjectId = sprint.ReadAttributeAsGuid("projectId"), Title = sprint.ReadChildValue("Title"), Slug = sprint.ReadChildValue("Slug")}).AsQueryable();
		}
	}
}